/****

    activequant - activestocks.eu

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License along
    with this program; if not, write to the Free Software Foundation, Inc.,
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

	
	contact  : contact@activestocks.eu
    homepage : http://www.activestocks.eu

****/
package org.activequant.dao.util;

import java.util.List;

import org.activequant.core.domainmodel.InstrumentSpecification;
import org.activequant.core.domainmodel.SeriesSpecification;
import org.activequant.core.domainmodel.data.MarketDataEntity;
import org.activequant.dao.IMarketDataEntityDao;
import org.activequant.dao.ISpecificationDao;
import org.activequant.util.exceptions.DaoException;
import org.activequant.util.tools.ArrayUtils;

/**
 * Common code for lookup decorators.<br/>
 * LookupDecorator&lt;T extends MarketDataEntity&lt;T&gt;&gt; implements the IMarketDataEntityDao&lt;T&gt; interface.<br/>
 * Holds the following associated variables:
 * <ul>
 * <li>decoree(IMarketDataEntityDao&lt;T&gt;)</li>
 * <li>spec(ISpecificationDao)</li>
 * <li>clazz(Class&lt;T&gt;)</li>
 * </ul>
 * <p>
 * <b>History:</b><br>
 *  - [24.10.2007] Created (Erik Nijkamp)<br>
 *  - [20.11.2007] Polished and fixed Ulrich's additions (Erik Nijkamp)<br>
 *
 *  @author Erik Nijkamp
 */
public class LookupDecorator<T extends MarketDataEntity<T>> implements IMarketDataEntityDao<T> {
	/**
	 * private IMarketDataEntityDao&lt;T&gt; decoree;
	 */
	private IMarketDataEntityDao<T> decoree;
	/**
	 * private ISpecificationDao spec;
	 */
	private ISpecificationDao spec;
	/**
	 * private Class&lt;T&gt; clazz;
	 */
	private Class<T> clazz;
	/**
	 * constructs a LookupDecorator(implements IMarketDataEntityDao&lt;T&gt;) using the given clazz(Class&lt;T&gt;), decoree(IMarketDataEntityDao&lt;T&gt;)
	 * and spec(ISpecificationDao) to set its associated clazz(Class&lt;T&gt;), decoree(IMarketDataEntityDao&lt;T&gt;) and spec(ISpecificationDao)
	 * @param clazz
	 * @param decoree
	 * @param spec
	 */
	public LookupDecorator(Class<T> clazz, IMarketDataEntityDao<T> decoree, ISpecificationDao spec) {
		this.clazz = clazz;
		this.decoree = decoree;
		this.spec = spec;
	}
	/**
	 * invokes <code>return decoree.count()</code> on the associated decoree(IMarketDataEntityDao&lt;T&gt;)
	 */
	public int count() throws DaoException {
		return decoree.count();
	}
	/**
	 * invokes <code>decoree.delete(entity)</code> on the associated decoree(IMarketDataEntityDao&lt;T&gt;)
	 */
	public void delete(T entity) throws DaoException {
		decoree.delete(entity);
	}
	/**
	 * invokes <code>decoree.delete(entities)</code> on the associated decoree(IMarketDataEntityDao&lt;T&gt;)
	 */
	public void delete(T... entities) throws DaoException {
		decoree.delete(entities);
	}
	/**
	 * invokes <code>decoree.delete(entities)</code> on the associated decoree(IMarketDataEntityDao&lt;T&gt;)
	 */
	public void delete(List<T> entities) throws DaoException {
		decoree.delete(entities);
	}
	/**
	 * invokes <code>decoree.deleteAll()</code> on the associated decoree(IMarketDataEntityDao&lt;T&gt;)
	 */
	public void deleteAll() throws DaoException {
		decoree.deleteAll();
	}
	/**
	 * invokes <code>return decoree.find(id)</code> on the associated decoree(IMarketDataEntityDao&lt;T&gt;)
	 */
	public T find(long id) throws DaoException {
		return decoree.find(id);
	}
	/**
	 * invokes <code>return decoree.findAll()</code> on the associated decoree(IMarketDataEntityDao&lt;T&gt;)
	 */
	public T[] findAll() throws DaoException {
		return decoree.findAll();
	}
	/**
	 * invokes <code>return decoree.findAllByExample(entity)</code> on the associated decoree(IMarketDataEntityDao&lt;T&gt;)
	 */
	public T[] findAllByExample(T entity) throws DaoException {
		return decoree.findAllByExample(entity);
	}
	/**
	 * invokes <code>return decoree.findByExample(entity)</code> on the associated decoree(IMarketDataEntityDao&lt;T&gt;)
	 */
	public T findByExample(T entity) throws DaoException {
		return decoree.findByExample(entity);
	}
	/**
	 * returns the given entity(T) after updating/saving it (if necessary)
	 */
	public T update(T entity) throws DaoException {
		// spec
		updateInstrumentSpecForEntity(entity);
		
		// check if this particular entity exists already. 
		try {			
			// entity not persistent
			if(!entity.hasId()) {
				// find by example or save entity
				T foundEntity = decoree.findByExample(entity);
				return foundEntity != null ? foundEntity : decoree.update(entity);
			} else {			
				// simple update
				return decoree.update(entity);
			}
		} catch(Exception ignored) {}
		
		return entity;		
	}
	/**
	 * returns the given entities(T...) after updating/saving each one (as necessary)
	 */
	public T[] update(T... entities) throws DaoException {
		for(int i = 0; i < entities.length; i++){
			entities[i] = update(entities[i]);
		}
		return entities;
	}
	/**
	 * returns the given entities(List&lt;T&gt;) after updating/saving each one (as necessary)
	 */
	public List<T> update(List<T> entities) throws DaoException {
		T[] array = ArrayUtils.asArray(entities, clazz);
		return ArrayUtils.asList(update(array));
	}
	/**
	 * if the instrumentSpecification(InstrumentSpecification) of the given entity(T) doesn't have an id(Long),
	 * it finds an InstrumentSpecification by invoking <code>spec.findByExample(entity.getInstrumentSpecification())</code> on the associated spec(ISpecificationDao), and then
	 * sets that InstrumentSpecification on the given entity(T)
	 * @param entity
	 * @throws DaoException
	 */
	private void updateInstrumentSpecForEntity(T entity) throws DaoException {
		if(!entity.getInstrumentSpecification().hasId()) {
			InstrumentSpecification resultSpec = spec.findByExample(entity.getInstrumentSpecification());
			if(resultSpec != null) {
				entity.setInstrumentSpecification(resultSpec);
			}
		}
	}
	/**
	 * invokes <code>decoree.deleteByInstrumentSpecification(spec)</code> on the associated decoree(IMarketDataEntityDao&lt;T&gt;)
	 * using the given spec(InstrumentSpecification)
	 */
	public void deleteByInstrumentSpecification(InstrumentSpecification spec)
			throws DaoException {
		decoree.deleteByInstrumentSpecification(spec);
	}
	/**
	 * invokes <code>decoree.deleteBySeriesSpecification(contractQuery)</code> on the associated decoree(IMarketDataEntityDao&lt;T&gt;)
	 * using the given contractQuery(SeriesSpecification)
	 */
	public void deleteBySeriesSpecification(SeriesSpecification contractQuery)
			throws DaoException {
		decoree.deleteBySeriesSpecification(contractQuery);
	}
	/**
	 * invokes <code>return decoree.findByInstrumentSpecification(spec)</code> on the associated decoree(IMarketDataEntityDao&lt;T&gt;)
	 * using the given spec(InstrumentSpecification)
	 */
	public T[] findByInstrumentSpecification(InstrumentSpecification spec)
			throws DaoException {
		return decoree.findByInstrumentSpecification(spec);
	}
	/**
	 * invokes <code>return decoree.findBySeriesSpecification(contractQuery)</code> on the associated decoree(IMarketDataEntityDao&lt;T&gt;)
	 * using the given contractQuery(SeriesSpecification)
	 */
	public T[] findBySeriesSpecification(SeriesSpecification contractQuery)
			throws DaoException {
		return decoree.findBySeriesSpecification(contractQuery);
	}

}
